/**
 * 折线角度测量工具类
 * 用于在Cesium场景中测量折线上相邻线段之间的夹角
 */
import * as Cesium from 'cesium'
export default class PolylineAngleMeasurer {
  /**
   * 构造函数
   * @param {Cesium.Viewer} viewer - Cesium Viewer实例
   * @param {Object} options - 配置选项
   */
  constructor(viewer, options = {}) {
    this.viewer = viewer;
    this.scene = viewer.scene;
    this.canvas = viewer.canvas;

    // 测量状态
    this.isMeasuring = false;
    this.points = []; // 折线点集合
    this.angles = []; // 计算的角度集合

    // 实体存储
    this.polylineEntity = null; // 折线实体
    this.pointEntities = []; // 点实体集合
    this.angleLabelEntities = []; // 角度标签实体集合
    this.tempLineEntity = null; // 临时线实体

    // 合并默认样式和用户自定义样式
    this.styles = {
      point: {
        color: Cesium.Color.RED,
        size: 6,
        outlineColor: Cesium.Color.WHITE,
        outlineWidth: 2,
        ...options.point
      },
      polyline: {
        color: Cesium.Color.YELLOW,
        width: 2,
        ...options.polyline
      },
      tempLine: {
        color: Cesium.Color.CYAN.withAlpha(0.7),
        width: 2,
        ...options.tempLine
      },
      angleLabel: {
        color: Cesium.Color.LIME,
        font: '14px sans-serif',
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 2,
        pixelOffset: new Cesium.Cartesian2(0, -15),
        ...options.angleLabel
      }
    };

    // 事件处理器
    this.handler = new Cesium.ScreenSpaceEventHandler(this.canvas);

    // 事件回调存储
    this.events = {};

    // 绑定方法上下文
    this._onClick = this._onClick.bind(this);
    this._onMouseMove = this._onMouseMove.bind(this);
  }

  /**
   * 开始测量
   */
  start() {
    if (this.isMeasuring) return;

    this.isMeasuring = true;
    this.clear(); // 清除之前的测量结果

    // 注册鼠标点击事件
    this.handler.setInputAction(this._onClick, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    // 注册鼠标移动事件
    this.handler.setInputAction(this._onMouseMove, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    this._triggerEvent('start', { timestamp: Date.now() });
    this.handler.setInputAction(() => {
      this.finish();
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  }

  /**
   * 结束测量
   */
  finish() {
    if (!this.isMeasuring) return;

    this.isMeasuring = false;

    // 移除事件监听
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    // 移除临时线
    if (this.tempLineEntity) {
      this.viewer.entities.remove(this.tempLineEntity);
      this.tempLineEntity = null;
    }

    this._triggerEvent('finish', {
      timestamp: Date.now(),
      points: this.getPoints(),
      angles: this.getAngles()
    });
  }

  /**
   * 清除所有测量结果
   */
  clear() {
    // 移除点实体
    this.pointEntities.forEach(entity => {
      this.viewer.entities.remove(entity);
    });

    // 移除折线实体
    if (this.polylineEntity) {
      this.viewer.entities.remove(this.polylineEntity);
      this.polylineEntity = null;
    }

    // 移除角度标签
    this.angleLabelEntities.forEach(entity => {
      this.viewer.entities.remove(entity);
    });

    // 移除临时线
    if (this.tempLineEntity) {
      this.viewer.entities.remove(this.tempLineEntity);
      this.tempLineEntity = null;
    }

    // 重置状态
    const oldPoints = this.points;
    const oldAngles = this.angles;

    this.points = [];
    this.angles = [];
    this.pointEntities = [];
    this.angleLabelEntities = [];

    this._triggerEvent('clear', {
      timestamp: Date.now(),
      oldPoints,
      oldAngles
    });
  }

  /**
   * 处理鼠标点击事件
   * @param {Object} movement - 包含位置信息的对象
   * @private
   */
  _onClick(movement) {
    // 将屏幕坐标转换为世界坐标
    const cartesian = this._getCartesianFromScreen(movement.position);
    if (!cartesian) return;

    // 添加点到集合
    this.points.push(cartesian);

    // 创建点实体
    const pointEntity = this._createPointEntity(cartesian);

    // 更新折线
    this._updatePolyline();

    this._triggerEvent('pointAdded', {
      index: this.points.length - 1,
      position: cartesian,
      entity: pointEntity
    });

    // 当有至少3个点时，计算最新的角度
    if (this.points.length >= 3) {
      const angleInfo = this._calculateNewAngle();
      this._triggerEvent('angleCalculated', angleInfo);
    }
  }

  /**
   * 处理鼠标移动事件
   * @param {Object} movement - 包含位置信息的对象
   * @private
   */
  _onMouseMove(movement) {
    // 没有点或测量已结束，不显示临时线
    if (this.points.length === 0 || !this.isMeasuring) return;

    // 移除之前的临时线
    if (this.tempLineEntity) {
      this.viewer.entities.remove(this.tempLineEntity);
    }

    // 创建新的临时线
    const cartesian = this._getCartesianFromScreen(movement.endPosition);
    if (cartesian) {
      this.tempLineEntity = this.viewer.entities.add({
        polyline: {
          positions: [this.points[this.points.length - 1], cartesian],
          width: this.styles.tempLine.width,
          material: this.styles.tempLine.color,
          clampToGround: true
        }
      });
    }
  }

  /**
   * 将屏幕坐标转换为世界坐标
   * @param {Cesium.Cartesian2} position - 屏幕坐标
   * @returns {Cesium.Cartesian3|null} 世界坐标
   * @private
   */
  _getCartesianFromScreen(position) {
    try {
      const ray = this.viewer.camera.getPickRay(position);
      if (!ray) return null;

      return this.scene.globe.pick(ray, this.scene);
    } catch (error) {
      console.error('坐标转换错误:', error);
      this._triggerEvent('error', {
        type: 'coordinateConversion',
        message: error.message,
        error
      });
      return null;
    }
  }

  /**
   * 创建点实体
   * @param {Cesium.Cartesian3} position - 点位置
   * @private
   */
  _createPointEntity(position) {
    const point = this.viewer.entities.add({
      position: position,
      point: {
        color: this.styles.point.color,
        pixelSize: this.styles.point.size,
        outlineColor: this.styles.point.outlineColor,
        outlineWidth: this.styles.point.outlineWidth,
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
      }
    });

    this.pointEntities.push(point);
    return point;
  }

  /**
   * 更新折线实体
   * @private
   */
  _updatePolyline() {
    // 如果已有折线实体，先移除
    if (this.polylineEntity) {
      this.viewer.entities.remove(this.polylineEntity);
    }

    // 创建新的折线实体
    this.polylineEntity = this.viewer.entities.add({
      polyline: {
        positions: this.points,
        width: this.styles.polyline.width,
        material: this.styles.polyline.color,
        clampToGround: true
      }
    });
  }

  /**
   * 计算最新添加的角度（最后三个点形成的角）
   * @private
   */
  _calculateNewAngle() {
    // 取最后三个点：A, B, C，其中B是顶点
    const idx = this.points.length - 3;
    const A = this.points[idx];
    const B = this.points[idx + 1];
    const C = this.points[idx + 2];

    // 计算向量BA和BC
    const BA = Cesium.Cartesian3.subtract(A, B, new Cesium.Cartesian3());
    const BC = Cesium.Cartesian3.subtract(C, B, new Cesium.Cartesian3());

    // 计算角度（弧度）
    const angleRadians = this._getAngleBetweenVectors(BA, BC);

    // 转换为角度并保留两位小数
    const angleDegrees = Cesium.Math.toDegrees(angleRadians).toFixed(2);

    // 存储角度信息
    const angleInfo = {
      vertex: B,
      value: angleDegrees,
      index: idx + 1, // 顶点索引
      points: { A, B, C },
      vectors: { BA, BC }
    };
    this.angles.push(angleInfo);

    // 创建角度标签
    const labelEntity = this._createAngleLabel(angleInfo);
    angleInfo.labelEntity = labelEntity;

    return angleInfo;
  }

  /**
   * 计算两个向量之间的角度（弧度）
   * @param {Cesium.Cartesian3} v1 - 向量1
   * @param {Cesium.Cartesian3} v2 - 向量2
   * @returns {number} 角度（弧度）
   * @private
   */
  _getAngleBetweenVectors(v1, v2) {
    // 计算点积
    const dotProduct = Cesium.Cartesian3.dot(v1, v2);

    // 计算向量模长
    const mag1 = Cesium.Cartesian3.magnitude(v1);
    const mag2 = Cesium.Cartesian3.magnitude(v2);

    // 防止除以零
    if (mag1 === 0 || mag2 === 0) return 0;

    // 计算余弦值
    let cosine = dotProduct / (mag1 * mag2);

    // 处理数值计算误差
    cosine = Cesium.Math.clamp(cosine, -1.0, 1.0);

    // 计算角度（弧度）
    return Math.acos(cosine);
  }

  /**
   * 创建角度标签
   * @param {Object} angleInfo - 角度信息
   * @private
   */
  _createAngleLabel(angleInfo) {
    const { vertex, value, index } = angleInfo;

    // 计算角平分线方向，确定标签位置
    const prevPoint = this.points[index - 1];
    const nextPoint = this.points[index + 1];

    // 计算向量
    const v1 = Cesium.Cartesian3.subtract(prevPoint, vertex, new Cesium.Cartesian3());
    const v2 = Cesium.Cartesian3.subtract(nextPoint, vertex, new Cesium.Cartesian3());

    // 归一化向量
    Cesium.Cartesian3.normalize(v1, v1);
    Cesium.Cartesian3.normalize(v2, v2);

    // 计算角平分线
    const bisector = Cesium.Cartesian3.add(v1, v2, new Cesium.Cartesian3());
    Cesium.Cartesian3.normalize(bisector, bisector);

    // 计算标签位置（从顶点沿角平分线偏移）
    const distance = Cesium.Cartesian3.distance(prevPoint, vertex) * 0.2;
    const labelPosition = Cesium.Cartesian3.multiplyByScalar(
      bisector,
      distance,
      new Cesium.Cartesian3()
    );
    Cesium.Cartesian3.add(vertex, labelPosition, labelPosition);

    // 创建标签实体
    const label = this.viewer.entities.add({
      position: labelPosition,
      label: {
        text: `∠${index}: ${value}°`,
        font: this.styles.angleLabel.font,
        fillColor: this.styles.angleLabel.color,
        outlineColor: this.styles.angleLabel.outlineColor,
        outlineWidth: this.styles.angleLabel.outlineWidth,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        pixelOffset: this.styles.angleLabel.pixelOffset,
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
      }
    });

    this.angleLabelEntities.push(label);
    return label;
  }

  /**
   * 触发事件
   * @param {string} eventName - 事件名称
   * @param {Object} data - 事件数据
   * @private
   */
  _triggerEvent(eventName, data) {
    if (this.events[eventName]) {
      this.events[eventName].forEach(callback => {
        try {
          callback(data);
        } catch (error) {
          console.error(`事件${eventName}的回调函数执行出错:`, error);
        }
      });
    }
  }

  /**
   * 注册事件监听
   * @param {string} eventName - 事件名称
   * @param {Function} callback - 回调函数
   */
  on(eventName, callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(callback);
  }

  /**
   * 移除事件监听
   * @param {string} eventName - 事件名称
   * @param {Function} callback - 要移除的回调函数
   */
  off(eventName, callback) {
    if (this.events[eventName]) {
      const index = this.events[eventName].indexOf(callback);
      if (index !== -1) {
        this.events[eventName].splice(index, 1);
      }
    }
  }

  /**
   * 获取所有测量的角度
   * @returns {Array} 角度信息数组
   */
  getAngles() {
    return [...this.angles];
  }

  /**
   * 获取所有测量点
   * @returns {Array} 点坐标数组
   */
  getPoints() {
    return [...this.points];
  }

  /**
   * 销毁工具
   */
  destroy() {
    this.finish();
    this.clear();
    this.handler.destroy();
    this.events = {};
    this.viewer = null;
    this.scene = null;
    this.canvas = null;
  }
}
